package org.ricks.net;

import org.ricks.ioc.Message;
import org.ricks.net.handler.IoServerConfig;
import org.ricks.net.transport.UdpAioSession;

import java.io.IOException;
import java.net.SocketAddress;
import java.util.concurrent.*;

/**
 * @author chenwei
 * @date 2020/8/2020:51
 */
public abstract class Server {

    /**
     * 服务ID
     */
    private boolean threadInit = false;
    private static int UID;
    private WorkDispatcher[] workerGroup;
    private ExecutorService executorService;
    /**
     * 服务配置
     */
    protected IoServerConfig config = new IoServerConfig();

    public abstract void start();

    protected void stop () {
        shutdown();
        if(threadInit) {
            for (WorkDispatcher dispatcher : workerGroup) {
                dispatcher.dispatch(WorkDispatcher.EXECUTE_TASK_OR_SHUTDOWN);
            }
            executorService.shutdown();
        }
    }

    protected abstract void shutdown();

    public Server() {
    }

    public Server(IoServerConfig config) {
        this.config = config;
    }

    protected synchronized void initThreadServer() throws IOException {

        int uid = UID++;
        threadInit = true;
        //启动worker线程组
        workerGroup = new WorkDispatcher[config.getThreadNum()];
        executorService = new ThreadPoolExecutor(config.getThreadNum(), config.getThreadNum(),
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(), new ThreadFactory() {
            int i = 0;

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "socket-" + uid + "-" + (++i));
            }
        });
        for (int i = 0; i < config.getThreadNum(); i++) {
            workerGroup[i] = new WorkDispatcher(config.getProcessor());
            executorService.execute(workerGroup[i]);
        }
    }


    public void dispatch(UdpAioSession aioSession, Message request, SocketAddress remote) {
        //理论上每个UDP包都是一个完整的消息
        if (request == null) {
            config.getProcessor().stateEvent(aioSession, StateMachineEnum.DECODE_EXCEPTION, new Exception("decode result is null"));
        } else {
            //任务分发
            workerGroup[(remote.hashCode() & Integer.MAX_VALUE) % workerGroup.length].dispatch( aioSession, request);
        }
    }

}
